#ifndef FILECOPIER_H
#define FILECOPIER_H

class QDir;
class QFileInfo;

#include <QMap>
#include <QSet>
#include <QString>

#include "generatoroutputview.h"

/**
  * This class is for copying files or entire directory hierarchies
  * from a source to a destination, while possibly replacing filenames and/or
  * keywords in text file contents along the way.
  */
class FileCopier
{
private:
    //
    // private members
    //
    const QString                  m_source;
    const QString                  m_destination;
    QDir                           m_srcBaseDir;
    QDir                           m_dstBaseDir;
    const QMap<QString, QString> * m_filenameSubstitutions;
    // OBS const QSet<QString>          * m_ignorePatterns;
    const QMap<QString, QString> * m_keywordSubstitutions;
    GeneratorOutputView          & m_outputView;

    const QRegExp                  m_keywordRegExp;
    QList<QRegExp>                 m_ignoreRegExps;

public:
    /**
      * Instantiates a copier that can copy files from one place to another
      * while possibly swapping their names and/or keywords in their text
      * contents.
      *
      * (a) If the source is a directory and if the destination exists,
      *     it also must be a directory.
      * (b) If the source is a directory and if the destination does not
      *     exist but it looks like a directory (no suffix or a
      *     trailing dir-separator), then destination is interpreted
      *     as directory and will be created.
      * (c) If the source is a file, then destination may be an existing
      *     directory or a nonexisting entity that looks like a directory.
      * (d) If the source is a file, then the destination may be an
      *     existing file or a nonexisting entity that looks like a file
      *     but in this case they must have the same suffix. NOTE: that the
      *     actual filename produced is subject to filename substitution,
      *     ie. even if the destination file existed, a totally new file
      *     may be created with the substituted filename.
      *
      * In case source and destination point to directories, the directory
      * hierarchy starting with source is traversed. Corresponding subdirectories
      * under destination are created if they don't yet exist. Corresponding
      * files under destination are created or overwritten.
      *
      * @param source the place to copy files from
      *
      * @param destination the place to copy files to
      *
      * @param filenameSubstitutions if a filename (without extension) matches
      *        any of the keys in the map, then the filename in the destination
      *        directory hierarchy will be the value for that key (plus
      *        extension of the original file. Optional, may be NULL.
      *
      * @param ignorePatterns is the set of filename patterns that are
      *        exceptions from keyword substitution. Optional, may be NULL,
      *        in which case no files are ignored. Pattern is the usual
      *        wildcard pattern: it can be a full file name or may have
      *        wildcard characters in it.
      *
      * @param keywordSubstitutions all files that are not to be ignored
      *        (cf ignorePatterns) will have all their lines scanned for
      *        occurrences of any of the keywords in the keywordSubstitutions
      *        map. All those occurrences will be swapped for the value for the
      *        key found. This process is done repeatedly, until no keyword is
      *        found in the line. Optional, may be NULL.
      *
      * @param outputView progress is reported through
      */
    FileCopier(const QString                & source,
               const QString                & destination,
               const QMap<QString, QString> * filenameSubstitutions,
               const QSet<QString>          * ignorePatterns,
               const QMap<QString, QString> * keywordSubstitutions,
               GeneratorOutputView          & outputView);


    /**
      * Starts the copying process.
      *
      * @return if all files were successfully copied.
      */
    bool copy();


private:
    //
    // implementation details
    //
    /**
      * @return true if the path exists and is a directory, or
      *         it does not exist, but the path does not have
      *         any suffixes or has a trailing directory separator.
      */
    static bool LooksLikeDir(const QFileInfo & file);

    /**
      * Copies a file to one place to another - verbatim.
      */
    bool copyFileVerbatim(const QFileInfo & srcFileInfo,
                          const QFileInfo & dstFileInfo);

    /**
      * @return a replacement for parameter line, with any
      *         keywords substituted in it.
      */
    QString substitute(const QString & line);


    /**
      * Copies a text file, performing keyword substituation on all
      * of its lines.
      */
    bool copyFileSubstituting(const QFileInfo & srcFileInfo,
                              const QFileInfo & dstFileInfo);

    /**
      * @return true if a given file is exempt from keyword substitution.
      */
    bool fileToBeIgnored(const QFileInfo & dstFileInfo);


    /**
      * Copies a file to destination directory. Precondition:
      * destination directory must exist.
      *
      * Filename and keyword translation happen here, if enabled.
      */
    bool copyFile(const QFileInfo & srcFileInfo,
                  const QDir      & dstBaseDir);


    /**
      * Copies the contents of source directory into another,
      * destination directory. Destination directory need not exist,
      * it will be created.
      */
    bool copyDir(const QDir & srcBaseDir,
                 const QDir & dstBaseDir);

};

#endif // FILECOPIER_H
